#include "paths.hpp"

#include <gvl/system/windows.hpp>
#include <ShlObj.h>

bool appendAppData(gvl::string& dest)
{
	char buf[MAX_PATH]; // Assumes TCHAR is char, will error otherwise
	BOOL ret = SHGetSpecialFolderPath(NULL, buf, CSIDL_APPDATA, TRUE);

	if(!ret)
		return false;

	dest.append(buf);
	return true;
}

PathType pathToNativePath(char const* str, gvl::string& dest)
{
	/* Path syntax:

	hierarchy	::= path-piece
	root-path	::= [hierarchy] '/' rel-path
	rel-path	::= path-piece ('/' path-piece)*

	path-piece	::= [A-Za-z0-9_. ]

	Examples, Windows:

	C:\Foo\Bar -> c/foo/bar
	C:\..Application Data..\ -> app/

	Examples, Linux:

	/home/foo -> /home/foo
	/home/foo/~barf/ -> app/
	*/

	uint8_t ch;
	char const* start = str;

	// Expect letters ended with '/'
	while(ch = (uint8_t)*str++)
	{
		if(!lj_ctype_isalpha(ch) && ch != '.' && ch != '/')
			return Path_Invalid;
			
		if(ch == '/')
		{
			break;
		}
	}

	if(!ch) return Path_Invalid; // No /

	char const* hierlist = "\3app\1.";

	int typeI = 0;
	// - 1 for excluding /
	int len = str - start - 1;

	for (typeI = 0; *(const uint8_t *)hierlist; ++typeI)
	{
		if (*(const uint8_t *)hierlist == len && memcmp(start, hierlist+1, len) == 0)
			break;
		hierlist += 1 + *(const uint8_t *)hierlist;
	}

	PathType type = (PathType)typeI;
	
#if GVL_WINDOWS
	if(type == Path_AppData)
	{
		if(!appendAppData(dest))
			return Path_Invalid;
		dest.append("\\barf\\");
		// TODO: If dest does not exist, we need to create it
	}
	else if(type == Path_WorkingDir)
	{
		dest.push_back('.');
		dest.push_back('\\');
	}
	else
	{
		dest.append(reinterpret_cast<uint8_t const*>(start), len);
		dest.push_back(':');
		dest.push_back('\\');
	}

	char prevch = ch;

	while(ch = (uint8_t)*str++)
	{
		if(!lj_ctype_isalnum(ch)
		&& ch != '_'
		&& ch != '.'
		&& ch != ' '
		&& ch != '/')
			return Path_Invalid;

		if(ch == '.' && prevch == '.')
			return Path_Invalid; // Disallow ..
		else if(ch == '/')
			dest.push_back('\\');
		else
			dest.push_back(ch);

		prevch = ch;
	}

#else
	#error "Not supported (yet)"
#endif

	return type;
}